﻿#region File Description

//-----------------------------------------------------------------------------
// MovieFetcher.cs
//
// Author: ITU Team3 (2012)
//-----------------------------------------------------------------------------

#endregion File Description

#region Using Statements

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;
using rentit03_server.Business;

#endregion Using Statements

namespace rentit03_server.OtherServices
{
    // TODO: input validation
    /// <summary>
    /// Class responsible for communicating with external web services
    /// </summary>
    public static class MovieFetcher
    {
        /// <summary>
        /// Pupulate a movie object with additional information from external web services.
        /// </summary>
        /// <param name="movie">A Movie object</param>
        /// <param name="apiService">The service you want to use</param>
        /// <returns>The populated Movie object</returns>
        public static RentitMovie FetchDataFromService(RentitMovie movie, ApiService apiService)
        {
            var request = GetRequest(movie, apiService);
            if (!request.Contains("error"))
            {
                switch (apiService)
                {
                    case ApiService.DeanClatworthy:
                        var o = MagicJSON.Deserialize<DeanClatworthyObject>(request);
                        if (!String.IsNullOrWhiteSpace(o.error))
                            break;

                        // Only continue if the correct movie was found
                        if (!(o.imdbid.Equals(movie.ImdbId) || (o.title.ToLower().Equals(movie.Title.ToLower()) && o.year >= movie.Year - 5 && o.year <= movie.Year + 5)))
                            break;

                        // Update imdb id
                        if (String.IsNullOrWhiteSpace(movie.ImdbId))
                            movie.ImdbId = o.imdbid;

                        // Always update rating
                        if (o.votes > 0)
                        {
                            var provider = new NumberFormatInfo { NumberDecimalSeparator = ".", NumberGroupSeparator = "," };
                            movie.Rating = (float)Convert.ToDouble(o.rating, provider);
                            movie.Votes = o.votes;
                        }

                        movie.Runtime = Runtime(o.runtime);

                        if (movie.Languages == null)
                            movie.Languages = new List<string>();

                        // Add languages
                        foreach (
                            var lan in
                                o.languages.Split(',').Select(s => s.Trim()).Select(
                                    language =>
                                    language.Replace("(onlyafewwords)", " (only a few words)").Replace(
                                        "(afewwords)", " (a few words)")))
                        {
                            movie.Languages.Add(lan);
                        }

                        if (movie.Genres == null)
                            movie.Genres = new List<RentitGenre>();

                        // Add genres
                        foreach (var genre in o.genres.Split(',').Select(s => s.Trim()))
                        {
                            movie.Genres.Add(new RentitGenre { MediaType = "Movie", Name = genre });
                        }

                        movie.ImdbUrl = o.imdburl;
                        movie.Year = o.year;

                        break;

                    case ApiService.ImdbApi:
                        ImdbApiObject imdbApiData;
                        try
                        {
                            imdbApiData = MagicJSON.Deserialize<ImdbApiObject>(request);
                        }
                        catch (Exception)
                        {
                            break;
                        }

                        if (!imdbApiData.Response)
                            break;

                        // Only continue if the correct movie was found
                        if (!(imdbApiData.imdbID.Equals(movie.ImdbId) || (imdbApiData.Title.ToLower().Equals(movie.Title.ToLower()) && imdbApiData.Year >= movie.Year - 5 && imdbApiData.Year <= movie.Year + 5)))
                        {
                            break;
                        }

                        //movie.Title = imdbApiData.Title;

                        movie.Year = imdbApiData.Year;

                        if (String.IsNullOrWhiteSpace(movie.Rated))
                            movie.Rated = imdbApiData.Rated;
                        if (String.IsNullOrWhiteSpace(movie.Description))
                            movie.Description = imdbApiData.Plot;
                        if (String.IsNullOrWhiteSpace(movie.Released))
                            movie.Released = imdbApiData.Released;

                        if (movie.Genres == null)
                            movie.Genres = new List<RentitGenre>();

                        foreach (var genre in imdbApiData.Genre.Split(',').Select(s => s.ToString().Trim()))
                        {
                            movie.Genres.Add(new RentitGenre { MediaType = "Movie", Name = genre });
                        }

                        movie.CoverUrl = imdbApiData.Poster;

                        // Update empty fields
                        if (movie.Votes == 0 && !imdbApiData.imdbRating.Equals("N/A"))
                        {
                            var provider = new NumberFormatInfo { NumberDecimalSeparator = ".", NumberGroupSeparator = "," };
                            movie.Rating = (float)Convert.ToDouble(imdbApiData.imdbRating, provider);
                            movie.Votes = (int)Convert.ToDouble(imdbApiData.imdbVotes, provider);
                        }

                        break;

                    case ApiService.TheMovieDb:
                        request = request.Remove(0, 1).Remove(request.Length - 2, 1);
                        var tmdbObject = (new JavaScriptSerializer()).Deserialize<TMDbObject>(request);

                        //Title += " (" + tmdbObject.original_name + ")";

                        break;
                }
            }
            return movie;
        }

        private static int Runtime(string runtime)
        {
            var min = 0;

            // Here we call Regex.Match.
            var match = Regex.Match(runtime, @"([0-9]+)min$", RegexOptions.IgnoreCase);

            // Here we check the Match instance.
            if (match.Success)
            {
                // Finally, we get the Group value and display it.
                min = Convert.ToInt16(match.Groups[1].Value);
            }

            return min;
        }

        public static string GetRequest(RentitMovie movie, ApiService apiService)
        {
            try
            {
                var request = WebRequest.Create(GetUrl(movie, apiService)) as HttpWebRequest;
                request.Accept = "application/json";
                using (var sreader = new System.IO.StreamReader(request.GetResponse().GetResponseStream()))
                {
                    return sreader.ReadToEnd();
                }
            }
            catch (WebException wex)
            {
                return "error: " + wex;
            }
            catch (Exception ex)
            {
                return "error" + ex;
            }
        }

        /// <summary>
        /// Generate url for external web service request.
        /// </summary>
        private static string GetUrl(RentitMovie movie, ApiService api)
        {
            var url = string.Empty;

            switch (api)
            {
                case ApiService.DeanClatworthy:
                    /*if (!String.IsNullOrWhiteSpace(movie.ImdbId))
                        url = "http://deanclatworthy.com/imdb/?id=" + movie.ImdbId;
                    else*/
                    if (!String.IsNullOrWhiteSpace(movie.Title))
                    {
                        url = "http://www.deanclatworthy.com/imdb/?q=" + HttpUtility.UrlEncode(movie.Title.Trim());

                        // If no year is stated, use year guessing
                        url += movie.Year > 0 ? "&year=" + movie.Year : "&yg=1";
                    }
                    break;

                case ApiService.ImdbApi:
                    if (!String.IsNullOrWhiteSpace(movie.ImdbId))
                        url = "http://www.imdbapi.com/?i=" + movie.ImdbId;
                    else
                        url = "http://www.imdbapi.com/?t=" + HttpUtility.UrlEncode(movie.Title.Trim()) + "&y=" + movie.Year;
                    break;

                case ApiService.TheMovieDb:
                    url = "http://api.themoviedb.org/2.1/Movie.imdbLookup/en/json/fc3380faeb2c6b817cfb9571ec2e59e2/" + movie.ImdbId;
                    break;
            }

            return url;
        }

        /// <summary>
        /// Supported web services.
        /// </summary>
        public enum ApiService
        {
            ImdbApi,
            DeanClatworthy,
            TheMovieDb
        }

        /// <summary>
        /// Representation of result from ImdbApi.
        /// </summary>
        private class ImdbApiObject
        {
            public string Title { get; set; }

            public int Year { get; set; }

            public string Rated { get; set; }

            public string Released { get; set; }

            public string Runtime { get; set; }

            public string Genre { get; set; }

            public string Director { get; set; }

            public string Writer { get; set; }

            public string Actors { get; set; }

            public string Plot { get; set; }

            public string Poster { get; set; }

            public string imdbRating { get; set; }

            public string imdbVotes { get; set; }

            public string imdbID { get; set; }

            public bool Response { get; set; }
        }

        /// <summary>
        /// Representation of result from Dean Clathworthy API.
        /// </summary>
        private class DeanClatworthyObject
        {
            public int code { get; set; }

            public string error { get; set; }

            public string imdbid { get; set; }

            public string imdburl { get; set; }

            public string genres { get; set; }

            public string languages { get; set; }

            public string country { get; set; }

            public int votes { get; set; }

            public int stv { get; set; }

            public int series { get; set; }

            public string rating { get; set; }

            public string title { get; set; }

            public string runtime { get; set; }

            public int year { get; set; }

            public int usascreens { get; set; }

            public int ukscreens { get; set; }
        }

        /// <summary>
        /// Representation of result from Tmdb API.
        /// </summary>
        public class TMDbObject
        {
            public int popularity { get; set; }

            public bool translated { get; set; }

            public bool adult { get; set; }

            public string language { get; set; }

            public string original_name { get; set; }

            public string name { get; set; }

            public string alternative_name { get; set; }

            public string movie_type { get; set; }

            public int id { get; set; }

            public string imdb_id { get; set; }

            public string url { get; set; }

            public int votes { get; set; }

            public double rating { get; set; }

            public string certification { get; set; }

            public string overview { get; set; }

            public string released { get; set; }

            public int runtime { get; set; }

            public string /*List<TMDbGenre>*/ genres { get; set; }

            public string /*List<TMDbPoster>*/ posters { get; set; }

            public string /*List<TMDbBackdrop>*/ backdrops { get; set; }

            public int version { get; set; }

            public string last_modified_at { get; set; }
        }

        public class TMDbGenre
        {
            public string type { get; set; }

            public string url { get; set; }

            public string name { get; set; }

            public int id { get; set; }
        }

        public class TMDbImage
        {
            public string type { get; set; }

            public string size { get; set; }

            public int height { get; set; }

            public int width { get; set; }

            public string url { get; set; }

            public string id { get; set; }
        }

        public class TMDbPoster
        {
            public TMDbImage TmDbImage { get; set; }
        }

        public class TMDbImage2
        {
            public string type { get; set; }

            public string size { get; set; }

            public int height { get; set; }

            public int width { get; set; }

            public string url { get; set; }

            public string id { get; set; }
        }

        public class TMDbBackdrop
        {
            public TMDbImage2 image { get; set; }
        }
    }
}